<?php
// +-------------------------------------------------------------------------------
// | DingZone [ A Rapid Development Framework For Dingtalk ]
// +-------------------------------------------------------------------------------
// | 模块管理相关Controller v1.0
// |
// | Copyright (c) 2014-2018 http://www.heimalanshi.com All rights reserved.
// | Author : Jie
// | Date : 2018-08-09
// +-------------------------------------------------------------------------------

namespace app\core\controller\site;


use app\core\model\CacheKey;
use app\core\model\Enterprise;
use app\core\model\EnterpriseModule;
use app\core\model\EnterpriseModuleApi;
use app\core\model\EnterpriseModuleAuthority;
use app\core\model\EnterpriseModuleConfig;
use app\core\model\SiteModule;
use app\core\model\SiteModuleApi;
use app\core\model\SiteModuleAuthority;
use app\core\model\SiteModuleConfig;
use app\core\model\SiteModuleMenu;
use app\core\model\SiteModuleWidget;
use app\core\model\CronTask;
use db\SqlRunner;
use ding\ApiHelper;
use module\ModuleLoader;

class ModuleController extends SiteBaseController {

    /**
     * ModuleController constructor.
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function __construct() {
        parent::__construct();
    }

    /**
     * 站点内的应用列表
     *
     * @param $status
     * @return \think\response\View
     * @throws \think\Exception
     * @throws \think\exception\DbException
     */
    public function all($status) {
        $modules = SiteModule::getAllModules($status);
        $this->assign('modules', $modules);
        return view();
    }

    /**
     * 模块信息
     *
     * @param $moduleName
     * @return \think\response\View
     * @throws \think\exception\DbException
     */
    public function detail($moduleName) {
        $moduleLoader = new ModuleLoader();

        $dbModule = SiteModule::getByName($moduleName);
        $localModule = $moduleLoader->info($moduleName);

        $module = [];
        if (empty($dbModule)) {
            // DB中不存在
            if (empty($localModule)) {
                // 本地不存在
                $this->error("未找到该模块");
            } else {
                // 本地存在(状态为待安装)
                $module = $localModule;
                $module['status'] = SiteModule::MODULE_STATUS_UNINSTALL;
            }
        } else {
            // DB中存在
            if (empty($localModule)) {
                // 本地不存在 TODO
                $this->error("该模块已被物理删除或者尚未下载");
            } else {
                // 本地存在
                $module = $dbModule;
            }
        }

        // 模块被哪些企业所用
        $enterprises = [];
        if (isset($module['id']) && $module['id']) {
            $cids = EnterpriseModule::getAllEidByMid($module['id']);
            $enterprises = Enterprise::batchGet($cids);
        }

        // api信息
        if (isset($module['id']) && $module['id']) {
            $apis = SiteModuleApi::getApis($module['id']);
        } else {
            $apis = $module['apis'];
        }
        if (is_string($apis)) {
            $apis = json_decode($apis, true);
        }
        if (!is_array($apis)) {
            $apis = [];
        }
        $apiInfos = self::_getApiInfos($apis);

        $this->assign("apiInfos", $apiInfos);
        $this->assign('module', $module);
        $this->assign('enterprises', $enterprises);
        $this->assign("initAction", input("init"));
        return view();
    }

    /**
     * 获取api信息
     *
     * @param $apis
     * @return array
     */
    private static function _getApiInfos($apis) {
        $apiInfos = [];
        foreach ($apis as $api) {
            $apiName = $api['api'];
            if (!array_key_exists($apiName, ApiHelper::$apis)) {
                continue;
            }
            $apiInfo = ApiHelper::$apis[$apiName];
            if (isset($apiInfo['privacySupportFields']) && !empty($api['grant_fields'])) {
                $fields = explode(',', $api['grant_fields']);
                $fieldInfos = [];
                foreach ($fields as $fieldName) {
                    $fieldInfos[$fieldName] = $apiInfo['privacySupportFields'][$fieldName];
                }
                $apiInfo['fieldInfos'] = $fieldInfos;
            }

            $apiInfos[$apiName] = $apiInfo;
        }

        return $apiInfos;
    }

    /**
     * 安装模块
     *
     * @param $moduleName
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function install($moduleName) {
        $dbModule = SiteModule::getByName($moduleName);
        if (!empty($dbModule)) {
            $this->error("此模块已经被安装成功，请勿重复安装");
        }

        $moduleLoader = new ModuleLoader();
        $localModule = $moduleLoader->info($moduleName);

        $data = [];
        $data['name'] = $localModule['name'];
        $data['version'] = $localModule['version'];
        $data['title'] = $localModule['title'];
        $data['description'] = $localModule['description'];
        $data['author'] = $localModule['author'];
        $data['url'] = $localModule['url'];
        $data['microapp'] = json_encode($localModule['microapp']);
        $data['status'] = SiteModule::MODULE_STATUS_ACTIVE;

        if (file_exists(ROOT_PATH . "addons/" . $moduleName . "/install.php")) {
            include_once ROOT_PATH . "addons/" . $moduleName . "/install.php";
        }
        if (file_exists(ROOT_PATH . "addons/" . $moduleName . "/install.sql")) {
            SqlRunner::runFile(ROOT_PATH . "addons/" . $moduleName . "/install.sql");
        }

        $mid = SiteModule::insert($data);
        if ($mid) {
            SiteModuleApi::createApis($mid, $localModule['apis']);
            SiteModuleMenu::createMenus($mid, $localModule['menus']);
            SiteModuleMenu::createEntries($mid, $localModule['entries']);
            SiteModuleAuthority::createAuthorities($mid, $localModule['authorities']);
            SiteModuleConfig::createConfigs($mid, $localModule['configs']);
            SiteModuleWidget::createWidgets($mid, $localModule['widgets']);
            CronTask::createModuleTasks($moduleName, $localModule['cronTasks']);

            CacheKey::remove("enterprise.menus");

            $this->success("模块安装成功");
        } else {
            $this->error("模块安装失败");
        }
    }

    /**
     * 卸载模块
     *
     * @param $moduleName
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function uninstall($moduleName) {
        $dbModule = SiteModule::getByName($moduleName);
        if (empty($dbModule)) {
            $this->error("此模块尚未安装，无需卸载");
        }
        if ($dbModule['status'] != SiteModule::MODULE_STATUS_INACTIVE) {
            $this->error("当前模块正在启用中，请先将模块禁用之后再进行卸载");
        }

        if (file_exists(ROOT_PATH . "addons/" . $moduleName . "/uninstall.php")) {
            include_once ROOT_PATH . "addons/" . $moduleName . "/uninstall.php";
        }
        if (file_exists(ROOT_PATH . "addons/" . $moduleName . "/uninstall.sql")) {
            SqlRunner::runFile(ROOT_PATH . "addons/" . $moduleName . "/uninstall.sql");
        }

        $ret = SiteModule::deleteById($dbModule['id']);
        if ($ret) {
            SiteModuleApi::deleteByMid($dbModule['id']);
            SiteModuleMenu::deleteByMid($dbModule['id']);
            SiteModuleAuthority::deleteByMid($dbModule['id']);
            SiteModuleConfig::deleteByMid($dbModule['id']);
            EnterpriseModule::deleteByMid($dbModule['id']);
            EnterpriseModuleApi::deleteByMid($dbModule['id']);
            EnterpriseModuleAuthority::deleteByMid($dbModule['id']);
            EnterpriseModuleConfig::deleteByMid($dbModule['id']);
            CronTask::deleteModuleTasks($moduleName);

            CacheKey::remove("enterprise.menus");

            $this->success("模块停用成功");
        } else {
            $this->error("模块停用失败");
        }
    }

    /**
     * 启用模块
     *
     * @param $moduleName
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function active($moduleName) {
        $dbModule = SiteModule::getByName($moduleName);
        if (empty($dbModule)) {
            $this->error("此模块尚未安装，请先进行安装");
        }
        if ($dbModule['status'] == SiteModule::MODULE_STATUS_ACTIVE) {
            $this->error("此模块已经被激活，请勿重复操作");
        }

        $ret = SiteModule::update(['status' => SiteModule::MODULE_STATUS_ACTIVE], $dbModule['id']);
        if ($ret) {
            $this->success("模块启用成功");
        } else {
            $this->error("模块启用失败");
        }
    }

    /**
     * 停用模块
     *
     * @param $moduleName
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function inactive($moduleName) {
        $dbModule = SiteModule::getByName($moduleName);
        if (empty($dbModule)) {
            $this->error("此模块尚未安装，请先进行安装");
        }
        if ($dbModule['status'] == SiteModule::MODULE_STATUS_INACTIVE) {
            $this->error("此模块已经被停用，请勿重复操作");
        }

        $ret = SiteModule::update(['status' => SiteModule::MODULE_STATUS_INACTIVE], $dbModule['id']);
        if ($ret) {
            $this->success("模块停用成功");
        } else {
            $this->error("模块停用失败");
        }
    }
}